#!/usr/bin/env python
# encoding: utf-8
"""
entity.py

Created by Morgan Quirk and Karl Gibson on 2007-11-02.
"""

class EntityHandler:
    def __init__(self, tick_time):
        self.entities = []              #all entities
        self.tick_time = tick_time      #time between ticks, in 100ths of a second

        self.entities_to_add = []       #ticks all of these immediately after adding
        self.entities_to_remove = []    #delete list

    #Ticks all entities currently in existence
    #new_clients: any new clients connecting to the game
    def tick(self, new_clients, dead_clients):
        [ent.tick(new_clients, dead_clients) for ent in self.entities]
        
        for ent in self.entities_to_add:
            ent.tick(new_clients, dead_clients)
            self.entities.append(ent)

        for ent in self.entities_to_remove:
            self.entities.remove(ent)

        self.entities_to_add = []
        self.entities_to_remove = []

    def add_entity(self, entity):
        self.entities_to_add.append(entity)
        entity.handler = self
        return entity
    
    def remove_entity(self, entity):
        self.entities_to_remove.append(entity)
        entity.handler = None

class Entity:
    def __init__(self):
        self.client = None          #client talking to this entity
        self.visible_to = []        #clients to send messages to

        self.client_actions = {}    #procedures to call when messages received from client
                                    #format: "message":action

        self.handler = None         #entity handler, set by the handler itself

    def tick(self, new_clients, dead_clients):
        [self.new_client(client) for client in new_clients]

        if self.client:
            [self.recv_client_message(msg) for msg in self.client.incoming_data]

        self.update()

        if self.client in dead_clients:
            self.dead_client()

        for client in dead_clients:
            if client in self.visible_to:
                self.visible_to.remove(client)

    #Executed once per tick for each new client
    def new_client(self, client):
        pass

    def recv_client_message(self, msg_list):
        command = msg_list[0]
        msg_list.remove(command)
        params = msg_list
        self.client_actions[command](*msg_list)

    #General object logic, executed once per tick
    def update(self):
        pass

    #Executed on tick if this entity's client dies
    def dead_client(self):
        pass

    def send_to_clients(self, *args):
        [client.message(*args) for client in self.visible_to]

#World: contains all areas in game.
#Area: individual places in the world.
# Friendly: players walk around freely and interact.  Contains players.
# Hostile: players walk around only in groups.  Instanced for each group (?).
#Tile: one player or group may occupy one at a time.  Makes up each area.
#Player: persistent data about a player.
#Group: players traveling together through a hostile area.  Contains players.  One per hostile area (?).

class World(Entity):
    def __init__(self, areas):
        Entity.__init__(self)

        self.players = []
        self.areas = []
        self.start_area = None
        
        for area in areas:
            self.areas.append(area)
            area.world = self

        self.start_area = areas[0]

    def new_client(self, client):
        self.players.append(Player(client, self.start_area))
        self.visible_to.append(client)


class Area(Entity):
    def __init__(self):
        Entity.__init__(self)

        self.players = []
        self.world = None

    def player_entered(self, player):
        self.players.append(player)
        self.area.visible_to.append(player.client)

    def player_exited(self, player):
        self.players.remove(player)
        self.visible_to.remove(player.client)


class HostileArea(Area):
    min_x = 0
    min_y = 0
    max_x = 0
    max_y = 0

    enter_x = 0
    enter_y = 0

    def __init__(self):
        Area.__init__(self)

    def player_entered(self, player):
        Area.player_entered(self, player)

class Group(entity):
    def __init__(self, leader):
        Entity.__init__(self)

        self.players = [leader]
        self.leader = leader
        self.x = 0
        self.y = 0

        leader.group = self

    def move(self, direction):
        if direction == "up":
            new_loc = (0,-1)
        elif direction == "down":
            new_loc = (0,1)
        elif direction == "left":
            new_loc = (-1,0)
        elif direction == "right":
            new_loc = (1,0)

        


class Player(Entity):
    def __init__(self, client, area):
        Entity.__init__(self)

        self.client = client
        self.name = client.name
        self.area = None
        self.group = None
        self.client_actions = {"chat":self.chat}

        self.enter_area(area)

    def enter_area(self, area):
        self.area = area
        self.area.player_entered(self)

    def exit_area(self):
        self.area.player_exited(self)
        self.area = None

    def chat(self, message):
        self.area.send_to_clients("chat", message)


"""
class GameController(Entity):
    def __init__(self):
        Entity.__init__(self)

        self.min_x = 0
        self.max_x = 639
        self.min_y = 0
        self.max_y = 479
        self.players = []

    def new_client(self, client):
        new_player = self.handler.add_entity(Player(client, self, self.max_x//2, self.max_y//2))
        self.players.append(new_player)
        self.visible_to.append(client)
        self.send_to_clients("newplayer",new_player.name,str(new_player.x),str(new_player.y))

    def remove_player(self, player):
        self.players.remove(player)
        self.handler.remove_entity(player)

class Player(Entity):
    def __init__(self, client, world, x, y):
        Entity.__init__(self)

        self.client = client
        self.name = client.name
        self.world = world
        self.x = x
        self.y = y
        self.xv=0
        self.yv=0

        self.client_actions = {"move":self.move}

    def new_client(self, client):
        client.message("player",self.name,str(self.x),str(self.y))
        self.visible_to.append(client)

    def update(self):
        self.x+=self.xv
        self.y+=self.yv
        self.send_to_clients("move",self.name,str(self.x),str(self.y))

    def dead_client(self):
        self.send_to_clients("killplayer",self.name)
        self.world.remove_player(self)

    def move(self, direction):
        distance = 4
        if direction == "up":
            self.yv -= distance
        elif direction == "down":
            self.yv += distance
        elif direction == "left":
            self.xv -= distance
        elif direction == "right":
            self.xv += distance
"""

"""
class Event:
    def __init__(self, entity, time, action, args):
        self.entity = entity
        self.time = time
        self.action = action
        self.args = args

    def tick(self, tick_time):
        self.time -= tick_time
        if self.time <= 0:
            self.action(self.entity, *self.args)

#Entity class, the basic object in the game
class Entity:
    def __init__(self):
        self.client = None          #client talking to this entity
        self.visible_to = []        #clients to send messages to

        self.parent = parent        #entity controlling this
        self.children = []          #entities controlled by this

    def add_child(self, new_ent):
        new_ent.parent = self
        self.children.append(new_ent)

    def del_child(self, ent):
        ent.parent = None
        self.children.remove(ent)

    #Updates self and children
    def tick(self, time_passed, new_clients):
        self.update(time_pased, new_clients)
        [ent.tick(time_passed, new_clients) for ent in self.children]
    
    #Main process loop, called repeatedly by parent
    #time_passed: ms since last update
    #new_clients: clients connected since last update

    def update(self, time_passed, new_clients):
        pass

    def find_client_input(self, client, input_msg):
        for data in client.incoming_data:
            data_list = data.split()
            if data_list[0] == input_msg:
                if len(data_list) > 1:
                    return data_list[1:]
                else:
                    return True
        return False

class GameController(Entity):
    def __init__(self):
        self.min_x = 0
        self.max_x = 639
        self.min_y = 0
        self.max_y = 479
        self.players = []

    def update(self, time_passed, new_clients):
        for client in new_clients:
            pass

class GameController(Entity):
    def __init__(self):
        Entity.__init__(self)
        self.min_x = 0
        self.max_x = 640
        self.min_y = 0
        self.min_y = 480
        self.players = []

    def update(self, time_passed, clients):
        for client in clients:
            new_player = self.find_client_input(client, "connect")
            if new_player:
                self.environment.add_entity(Player(new_player[0], client, self))
                #print "asdfadsf"
                [client.outgoing_data.append("newplayer " + new_player[0]) for client in clients]

class Player(Entity):
    def __init__(self, name, client, controller):
        Entity.__init__(self)
        self.x = 0
        self.y = 0
        self.name = name
        self.client = client
        self.controller = controller

    def update(self, time_passed, clients):
        movement = self.find_client_input(self.client, "move")
        if movement:
            self.move(movement[0],4)
            [client.outgoing_data.append("move " + self.name + " " + str(self.x) + " " + str(self.y)) for client in clients]
        disconnect = self.find_client_input(self.client, "disconnect")
        if disconnect:
            self.die()
            [client.outgoing_data.append("removeplayer " + self.name) for client in clients]

    def die(self):
        self.controller.players.remove(self)
        self.environment.remove_entity(self)

    def move(self, direction, distance):
        if direction == "up":
            self.y -= distance
        elif direction == "down":
            self.y += distance
        elif direction == "left":
            self.x -= distance
        elif direction == "right":
            self.x += distance
"""